home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / channel.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  25KB  |  1,101 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.  See the file COPYING for details.
  4.  
  5.    $Id: channel.c,v 1.61 2001/02/15 08:39:45 drscholl Exp $ */
  6.  
  7. #include <stdio.h>
  8. #include <limits.h>
  9. #include <string.h>
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13. #include "opennap.h"
  14. #include "debug.h"
  15.  
  16. /* load the predefined channels */
  17. void
  18. load_channels (void)
  19. {
  20.     char    path[_POSIX_PATH_MAX], *name, *slimit, *slevel, *topic, *ptr;
  21.     char    realname[256];
  22.     FILE   *fp;
  23.     int     limit, level, line = 0;
  24.     CHANNEL *chan;
  25.     int     version = 0;
  26.  
  27.     snprintf (path, sizeof (path), "%s/channels", Config_Dir);
  28.     fp = fopen (path, "r");
  29.     if (!fp)
  30.     {
  31.     if (errno != ENOENT)
  32.         logerr ("load_channels", path);
  33.     return;
  34.     }
  35.     if (fgets (Buf, sizeof (Buf), fp) == NULL)
  36.     {
  37.     fclose (fp);
  38.     return;
  39.     }
  40.     if (!strncmp (":version 1", Buf, 10))
  41.     version = 1;
  42.     else
  43.     rewind (fp);
  44.  
  45.     while (fgets (Buf, sizeof (Buf), fp))
  46.     {
  47.     line++;
  48.     ptr = Buf;
  49.     while (ISSPACE (*ptr))
  50.         ptr++;
  51.     if (*ptr == 0 || (version == 0 && *ptr == '#'))
  52.         continue;        /* blank or comment line */
  53.     name = next_arg (&ptr);
  54.     slimit = next_arg (&ptr);
  55.     slevel = next_arg (&ptr);
  56.     topic = next_arg (&ptr);
  57.     if (!name || !slimit || !slevel || !topic)
  58.     {
  59.         log ("load_channels: %s:%d: too few parameters", path, line);
  60.         continue;
  61.     }
  62.     /* force new channel name restrictions */
  63.     if (option (ON_IRC_CHANNELS) && *name != '#' && *name != '&')
  64.     {
  65.         snprintf (realname, sizeof (realname), "#%s", name);
  66.         name = realname;
  67.     }
  68.     if (invalid_channel (name))
  69.     {
  70.         log ("load_channels: %s:%d: %s: invalid channel name", name);
  71.         continue;
  72.     }
  73.     level = get_level (slevel);
  74.     if (level == -1)
  75.     {
  76.         log ("load_channels: %s:%d: %s: invalid level",
  77.          path, line, slevel);
  78.         continue;
  79.     }
  80.     limit = atoi (slimit);
  81.     if (limit < 0 || limit > 65535)
  82.     {
  83.         log ("load_channels: %s:%d: %d: invalid limit",
  84.          path, line, limit);
  85.         continue;
  86.     }
  87.     chan = hash_lookup (Channels, name);
  88.     if (chan)
  89.     {
  90.         log ("load_channels: %s:%d: %s is already defined", path, line,
  91.          name);
  92.         continue;
  93.     }
  94.     chan = CALLOC (1, sizeof (CHANNEL));
  95.     if (chan)
  96.     {
  97.         chan->name = STRDUP (name);
  98.         chan->topic = STRDUP (topic);
  99.         chan->limit = limit;
  100.         chan->level = level;
  101.         chan->flags = ON_CHANNEL_REGISTERED;
  102.         chan->timestamp = global.current_time;
  103.     }
  104.     if (hash_add (Channels, chan->name, chan))
  105.         free_channel (chan);
  106.     }
  107.     fclose (fp);
  108. }
  109.  
  110. static void
  111. dump_channel_cb (CHANNEL * chan, FILE * fp)
  112. {
  113.     /* only save registered channels */
  114.     if (chan->flags & ON_CHANNEL_REGISTERED)
  115.     {
  116.     fprintf (fp, "%s %d %s \"%s\"", chan->name, chan->limit,
  117.          Levels[chan->level], chan->topic);
  118. #ifdef WIN32
  119.     fputc ('\r', fp);
  120. #endif
  121.     fputc ('\n', fp);
  122.     }
  123. }
  124.  
  125. void
  126. dump_channels (void)
  127. {
  128.     char    path[_POSIX_PATH_MAX];
  129.     FILE   *fp;
  130.  
  131.     snprintf (path, sizeof (path), "%s/channels", Config_Dir);
  132.     fp = fopen (path, "w");
  133.     if (!fp)
  134.     {
  135.     logerr ("dump_channels", path);
  136.     return;
  137.     }
  138.     fputs (":version 1", fp);
  139. #ifdef WIN32
  140.     fputc ('\r', fp);
  141. #endif
  142.     fputc ('\n', fp);
  143.     hash_foreach (Channels, (hash_callback_t) dump_channel_cb, fp);
  144.     if (fclose (fp))
  145.     logerr ("dump_channels", "fclose");
  146. }
  147.  
  148. /* 422/423 [ :<sender> ] <channel> <user!ip> ["<reason>"]
  149.  * (un)ban a user/ip from the channel
  150.  */
  151. HANDLER (channel_ban)
  152. {
  153.     CHANNEL *chan;
  154.     char   *av[2], *sender;
  155.     int     ac = -1;
  156.     LIST  **list, *tmp;
  157.     BAN    *b = 0;
  158.     char   *banptr, realban[256];
  159.     USER   *senderUser;
  160.     int     found = 0;
  161.  
  162.     (void) len;
  163.     ASSERT (validate_connection (con));
  164.     if (pop_user_server (con, tag, &pkt, &sender, &senderUser))
  165.     return;
  166.     if (pkt)
  167.     ac = split_line (av, FIELDS (av), pkt);
  168.     if (ac < 2)
  169.     {
  170.     unparsable (con);
  171.     return;
  172.     }
  173.     chan = hash_lookup (Channels, av[0]);
  174.     if (!chan)
  175.     {
  176.     if (ISUSER (con))
  177.         send_cmd (con, MSG_SERVER_NOSUCH,
  178.               "channel ban failed: no such channel");
  179.     return;
  180.     }
  181.  
  182.     if (ISSERVER (con) && chan->local)
  183.     {
  184.     log ("channel_ban: server %s accessed local channel %s", con->host,
  185.          chan->name);
  186.     return;
  187.     }
  188.  
  189.     /* check for permission */
  190.     if (senderUser && senderUser->level < LEVEL_MODERATOR
  191.     && !is_chanop (chan, senderUser))
  192.     {
  193.     if (ISUSER (con))
  194.         send_cmd (con, MSG_SERVER_NOSUCH,
  195.             "channel ban failed: you are not operator");
  196.     return;
  197.     }
  198.  
  199.     banptr = normalize_ban (av[1], realban, sizeof (realban));
  200.  
  201.     /* ensure this user/ip is not already banned */
  202.     for (list = &chan->bans; *list; list = &(*list)->next)
  203.     {
  204.     b = (*list)->data;
  205.     if (!strcasecmp (b->target, banptr))
  206.     {
  207.         if (tag == MSG_CLIENT_CHANNEL_BAN)
  208.         return;        /* ignore, already banned */
  209.         else
  210.         {
  211.         /* unban */
  212.         ASSERT (tag == MSG_CLIENT_CHANNEL_UNBAN);
  213.         tmp = *list;
  214.         *list = (*list)->next;
  215.         FREE (tmp);
  216.         free_ban (b);
  217.         found = 1;
  218.         }
  219.         break;
  220.     }
  221.     }
  222.  
  223.     if (ac > 2)
  224.     truncate_reason (av[2]);
  225.  
  226.     if (tag == MSG_CLIENT_CHANNEL_BAN)
  227.     {
  228.     /* new ban */
  229.     b = CALLOC (1, sizeof (BAN));
  230.     if (b)
  231.     {
  232.         b->setby = STRDUP (sender);
  233.         b->target = STRDUP (banptr);
  234.         b->when = global.current_time;
  235.         if (ac > 2)
  236.         b->reason = STRDUP (av[2]);
  237.     }
  238.     if (!b || !b->setby || !b->target || (ac > 2 && !b->reason))
  239.     {
  240.         OUTOFMEMORY ("channel_ban");
  241.         return;
  242.     }
  243.     tmp = CALLOC (1, sizeof (LIST));
  244.     if (!tmp)
  245.     {
  246.         OUTOFMEMORY ("channel_ban");
  247.         free_ban (b);
  248.         return;
  249.     }
  250.     tmp->data = b;
  251.     chan->bans = list_push (chan->bans, tmp);
  252.     }
  253.     else if (!found)
  254.     {
  255.     /* attempted to unban something that wasn't banned */
  256.     if (ISUSER (con))
  257.         send_cmd (con, MSG_SERVER_NOSUCH,
  258.               "channel unban failed: no such ban");
  259.     return;
  260.     }
  261.  
  262.     /* don't reference `b' here since it is free'd when unbanning */
  263.  
  264.     if (!chan->local)
  265.     pass_message_args (con, tag, ":%s %s %s \"%s\"",
  266.                sender, chan->name, banptr,
  267.                (ac > 2) ? av[2] : "");
  268.  
  269.     notify_ops (chan, "%s%s %sbanned %s from %s: %s",
  270.         !senderUser ? "Server " : "",
  271.         sender, (tag == MSG_CLIENT_CHANNEL_UNBAN) ? "un" : "",
  272.         banptr, chan->name, (ac > 2) ? av[2] : "");
  273. }
  274.  
  275. /* 420 <channel> */
  276. HANDLER (channel_banlist)
  277. {
  278.     CHANNEL *chan;
  279.     LIST   *list;
  280.     BAN    *b;
  281.  
  282.     (void) len;
  283.     CHECK_USER_CLASS ("channel_banlist");
  284.     chan = hash_lookup (Channels, pkt);
  285.     if (!chan)
  286.     {
  287.     nosuchchannel (con);
  288.     return;
  289.     }
  290.     for (list = chan->bans; list; list = list->next)
  291.     {
  292.     b = list->data;
  293.     /* TODO: i have no idea what the real format of this is.  nap v1.0
  294.        just displays whatever the server returns */
  295.     send_cmd (con, MSG_SERVER_CHANNEL_BAN_LIST,
  296.           "%s %s \"%s\" %u %d", b->target, b->setby,
  297.           NONULL (b->reason), (int) b->when, b->timeout);
  298.     }
  299.     /* TODO: i assume the list is terminated in the same fashion the other
  300.        list commands are */
  301.     send_cmd (con, tag, "");
  302. }
  303.  
  304. void
  305. sync_channel_bans (CONNECTION * con, CHANNEL * chan)
  306. {
  307.     LIST   *list;
  308.     BAN    *banptr;
  309.  
  310.     ASSERT (chan->local == 0);
  311.     for (list = chan->bans; list; list = list->next)
  312.     {
  313.     banptr = list->data;
  314.     send_cmd (con, MSG_CLIENT_CHANNEL_BAN,
  315.           ":%s %s %s \"%s\"",
  316.           Server_Name,
  317.           chan->name, banptr->target, NONULL (banptr->reason));
  318.     }
  319. }
  320.  
  321. /* 424 [ :<sender> ] <channel> */
  322. HANDLER (channel_clear_bans)
  323. {
  324.     USER   *sender;
  325.     CHANNEL *chan;
  326.  
  327.     (void) len;
  328.     ASSERT (validate_connection (con));
  329.     if (pop_user (con, &pkt, &sender))
  330.     return;
  331.     if (!pkt)
  332.     {
  333.     unparsable (con);
  334.     return;
  335.     }
  336.     chan = hash_lookup (Channels, pkt);
  337.     if (!chan)
  338.     {
  339.     nosuchchannel (con);
  340.     return;
  341.     }
  342.  
  343.     if (ISSERVER (con) && chan->local)
  344.     {
  345.     log ("clear_channel_bans: server %s accessed local channel %s",
  346.          con->host, chan->name);
  347.     return;
  348.     }
  349.  
  350.     if (sender->level < LEVEL_MODERATOR)
  351.     {
  352.     if (list_find (sender->channels, chan) == 0)
  353.     {
  354.         /* not on the channel */
  355.         if (ISUSER (con))
  356.         send_cmd (con, MSG_SERVER_NOSUCH,
  357.             "channel ban clear failed: you are not on that channel");
  358.         return;
  359.     }
  360.     else if (!is_chanop (chan, sender))
  361.     {
  362.         if (ISUSER (con))
  363.         send_cmd (con, MSG_SERVER_NOSUCH,
  364.             "channel ban clear failed: you are not channel operator");
  365.         return;
  366.     }
  367.     }
  368.  
  369.     /* pass just in case servers are desynched */
  370.     if (!chan->local)
  371.     pass_message_args (con, tag, ":%s %s", sender->nick, chan->name);
  372.  
  373.     if (!chan->bans)
  374.     {
  375.     if (ISUSER (con))
  376.         send_cmd (con, MSG_SERVER_NOSUCH, "There are no bans");
  377.     return;
  378.     }
  379.     list_free (chan->bans, (list_destroy_t) free_ban);
  380.     chan->bans = 0;
  381.     notify_ops (chan, "%s cleared the ban list on %s", sender->nick,
  382.         chan->name);
  383. }
  384.  
  385. CHANUSER *
  386. find_chanuser (LIST * list, USER * user)
  387. {
  388.     CHANUSER *chanUser;
  389.  
  390.     for (; list; list = list->next)
  391.     {
  392.     chanUser = list->data;
  393.     ASSERT (chanUser->magic == MAGIC_CHANUSER);
  394.     if (chanUser->user == user)
  395.         return chanUser;
  396.     }
  397.     return 0;
  398. }
  399.  
  400. static void
  401. mass_deop (CHANNEL *chan)
  402. {
  403.     CHANUSER *cu;
  404.     LIST *list;
  405.  
  406.     for (list = chan->users; list; list=list->next)
  407.     {
  408.     cu = list->data;
  409.     if (cu->flags & ON_CHANNEL_OPERATOR)
  410.     {
  411.         cu->flags &= ~ON_CHANNEL_OPERATOR;
  412.         if (ISUSER (cu->user->con))
  413.         {
  414.         send_cmd (cu->user->con, MSG_SERVER_NOSUCH, "%s deopped you on channel %s: timestamp",
  415.             Server_Name, chan->name);
  416.         /* don't bother with a notify_chanops() since all ops are
  417.          * currently invalid.
  418.          */
  419.         }
  420.     }
  421.     }
  422. }
  423.  
  424. /* icky, but we need to find the timestamp quickly.  this is the max number
  425.  * of ops/voice that can appear on one line
  426.  */
  427. #define MAX_OPS    6
  428.  
  429. /* 10204/10205 [ :<sender> ] <channel> <nick> [nick ... [:timestamp] ]
  430.  * 10211/10212
  431.  * op/deop/voice/unvoice channel user
  432.  */
  433. HANDLER (channel_op)
  434. {
  435.     char   *sender;
  436.     CHANNEL *chan;
  437.     CHANUSER *chanUser = 0;
  438.     USER   *user, *senderUser = 0;
  439.     int     ac = -1;
  440.     char   *av[MAX_OPS + 2];
  441.     int     j;
  442.     char   *ops = 0;
  443.     int     ts;
  444.     int     bit;
  445.     int     give;
  446.     char   *desc;        /* description of operation */
  447.  
  448.     ASSERT (validate_connection (con));
  449.  
  450.     (void) len;
  451.     if (pop_user_server (con, tag, &pkt, &sender, &senderUser))
  452.     return;
  453.     if (pkt)
  454.     ac = split_line (av, FIELDS (av), pkt);
  455.  
  456.     if (ac < 1)
  457.     {
  458.     unparsable (con);
  459.     return;
  460.     }
  461.  
  462.     chan = hash_lookup (Channels, av[0]);
  463.     if (!chan)
  464.     {
  465.     nosuchchannel (con);
  466.     return;
  467.     }
  468.  
  469.     if (tag == MSG_CLIENT_OP)
  470.     {
  471.     bit = ON_CHANNEL_OPERATOR;
  472.     give = 1;
  473.     desc = "opp";
  474.     }
  475.     else if (tag == MSG_CLIENT_DEOP)
  476.     {
  477.     bit = ON_CHANNEL_OPERATOR;
  478.     give = 0;
  479.     desc = "deopp";
  480.     }
  481.     else if (tag == MSG_CLIENT_CHANNEL_VOICE)
  482.     {
  483.     bit = ON_CHANNEL_VOICE;
  484.     give = 1;
  485.     desc = "voic";
  486.     }
  487.     else
  488.     {
  489.     ASSERT (tag == MSG_CLIENT_CHANNEL_UNVOICE);
  490.     bit = ON_CHANNEL_VOICE;
  491.     give = 0;
  492.     desc = "devoic";
  493.     }
  494.  
  495.     if (ac == 1)
  496.     {
  497.     LIST   *list;
  498.  
  499.     /*user requested a list */
  500.     CHECK_USER_CLASS ("channel_op");
  501.  
  502.     send_cmd (con, MSG_CLIENT_PRIVMSG,
  503.           "ChanServ %sed users on channel %s:", desc, chan->name);
  504.     for (list = chan->users; list; list = list->next)
  505.     {
  506.         chanUser = list->data;
  507.         if (chanUser->flags & bit)
  508.         send_cmd (con, MSG_CLIENT_PRIVMSG, "ChanServ %s",
  509.               chanUser->user->nick);
  510.     }
  511.     return;
  512.     }
  513.  
  514.     /* check timestamp if present */
  515.     if (ISSERVER (con))
  516.     {
  517.     if (chan->local)
  518.     {
  519.         log ("channel_op: server %s accessed local channel %s", con->host,
  520.          chan->name);
  521.         return;
  522.     }
  523.  
  524.     if (*av[ac - 1] == ':')
  525.     {
  526.         ts = atoi (av[ac - 1] + 1);
  527.  
  528.         ac--;        /* don't count this in the loops below */
  529.  
  530.         if (chan->timestamp > 0)
  531.         {
  532.         if (ts > chan->timestamp)
  533.         {
  534.             /* remote server is desynced */
  535.             log ("channel_op: newer TS for channel %s from server %s",
  536.                 chan->name, con->host);
  537.             log ("channel_op: ts=%d chan->timestamp=%u", ts,
  538.                 chan->timestamp);
  539.             return;    /* ignore it */
  540.         }
  541.         else if (ts < chan->timestamp)
  542.         {
  543.             /* channel existed on remote server prior to creation
  544.              * on this server, deop everyone that we know
  545.              * about
  546.              */
  547.             log ("channel_op: older TS for channel %s from server %s",
  548.                 chan->name, con->host);
  549.             log ("channel_op: ts=%d chan->timestamp=%u", ts,
  550.                 chan->timestamp);
  551.  
  552.             mass_deop (chan);
  553.         }
  554.         }
  555.         chan->timestamp = ts;    /* update */
  556.     }
  557.     }
  558.  
  559.     /* check for permission */
  560.     if (senderUser && senderUser->level < LEVEL_MODERATOR)
  561.     {
  562.     /* if not a mod+, user must be a chanop on the channel */
  563.     if (!is_chanop (chan, senderUser))
  564.     {
  565.         if (ISUSER (con))
  566.         {
  567.         send_cmd (con, MSG_SERVER_NOSUCH,
  568.               "channel %s failed: you are not channel operator",
  569.               desc);
  570.         }
  571.         else
  572.         {
  573.         /* desync */
  574.         log ("channel_op: %s is not opped on channel %s",
  575.             senderUser->nick, chan->name);
  576.         }
  577.         return;
  578.     }
  579.     }
  580.  
  581.     for (j = 1; j < ac; j++)
  582.     {
  583.     user = hash_lookup (Users, av[j]);
  584.     if (user)
  585.     {
  586.         chanUser = find_chanuser (chan->users, user);
  587.         if (chanUser)
  588.         {
  589.         if (give)
  590.         {
  591.             if ((chanUser->flags & bit) == 0)
  592.             {
  593.             /* not opped yet */
  594.             if (ISUSER (user->con))
  595.                 send_cmd (user->con, MSG_SERVER_NOSUCH,
  596.                       "%s%s %sed you on channel %s",
  597.                       !senderUser ? "Server " : "",
  598.                       sender, desc, chan->name);
  599.             notify_ops (chan,
  600.                     "%s%s %sed %s on channel %s",
  601.                     !senderUser ? "Server " : "",
  602.                     sender, desc, user->nick, chan->name);
  603.             chanUser->flags |= bit;
  604.             if (!chan->local)
  605.                 ops = append_string (ops, " %s", user->nick);
  606.             }
  607.         }
  608.         else
  609.         {
  610.             ASSERT (give == 0);
  611.             if (chanUser->flags & bit)
  612.             {
  613.             if (ISUSER (user->con))
  614.                 send_cmd (user->con, MSG_SERVER_NOSUCH,
  615.                       "%s%s %sed you on channel %s",
  616.                       !senderUser ? "Server " : "",
  617.                       sender, desc, chan->name);
  618.             notify_ops (chan,
  619.                     "%s%s %sed %s on channel %s",
  620.                     !senderUser ? "Server " : "",
  621.                     sender, desc, user->nick, chan->name);
  622.             chanUser->flags &= ~bit;
  623.             if (!chan->local)
  624.                 ops = append_string (ops, " %s", user->nick);
  625.             }
  626.         }
  627.         }
  628.         else
  629.         {
  630.         if (ISUSER (con))
  631.             send_cmd (con, MSG_SERVER_NOSUCH,
  632.                   "channel %s failed: user is not on channel",
  633.                   desc);
  634.         }
  635.     }
  636.     else
  637.     {
  638.         if (ISUSER (con))
  639.         send_cmd (con, MSG_SERVER_NOSUCH,
  640.               "channel %s failed: no such user", desc);
  641.     }
  642.     }
  643.  
  644.     /* if anything changed, pass along info to peer servers */
  645.     if (ops)
  646.     {
  647.     ASSERT (chan->local == 0);
  648.     /* pass the message on to the other servers */
  649.     pass_message_args (con, tag, ":%s %s %s :%u", sender, chan->name,
  650.                ops, chan->timestamp);
  651.     FREE (ops);
  652.     }
  653. }
  654.  
  655. void
  656. notify_ops (CHANNEL * chan, const char *fmt, ...)
  657. {
  658.     LIST   *list;
  659.     CHANUSER *chanUser;
  660.     char    buf[256];
  661.     int     len;
  662.  
  663.     va_list ap;
  664.  
  665.     va_start (ap, fmt);
  666.     vsnprintf (buf + 4, sizeof (buf) - 4, fmt, ap);
  667.     va_end (ap);
  668.     len = strlen (buf + 4);
  669.     set_len (buf, len);
  670.     set_tag (buf, MSG_SERVER_NOSUCH);
  671.     for (list = chan->users; list; list = list->next)
  672.     {
  673.     chanUser = list->data;
  674.     ASSERT (chanUser->magic == MAGIC_CHANUSER);
  675.     if (ISUSER (chanUser->user->con) &&
  676.         ((chanUser->flags & ON_CHANNEL_OPERATOR) ||
  677.          chanUser->user->level > LEVEL_USER))
  678.         queue_data (chanUser->user->con, buf, 4 + len);
  679.     }
  680. }
  681.  
  682. /* 10208 [ :<sender> ] <channel> <text>
  683.    sends a message to all channel ops/mods on a given channel */
  684. HANDLER (channel_wallop)
  685. {
  686.     USER   *sender;
  687.     CHANNEL *chan;
  688.     char   *chanName;
  689.     char   *sender_name;
  690.  
  691.     (void) len;
  692.     ASSERT (validate_connection (con));
  693.  
  694.     if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
  695.     return;
  696.  
  697.     chanName = next_arg (&pkt);
  698.     if (!chanName || !pkt)
  699.     {
  700.     unparsable (con);
  701.     return;
  702.     }
  703.     chan = hash_lookup (Channels, chanName);
  704.     if (!chan)
  705.     {
  706.     if (ISUSER (con))
  707.         send_cmd (con, MSG_SERVER_NOSUCH,
  708.               "channel wallop failed: no such channel");
  709.     return;
  710.     }
  711.     if (sender && sender->level < LEVEL_MODERATOR
  712.     && !is_chanop (chan, sender))
  713.     {
  714.     if (ISUSER (con))
  715.         send_cmd (con, MSG_SERVER_NOSUCH,
  716.               "channel wallop failed: you are not channel operator");
  717.     return;
  718.     }
  719.     /* NOTE: there is no check to make sure the sender is actually a member
  720.        of the channel.  this should be ok since channel ops have to be present
  721.        in the channel to issue the command (since they would not have op
  722.        status otherwise, and is_chanop() will fail).  mods+ are assumed to
  723.        be trusted enough that the check for membership is not required. */
  724.     if (!chan->local)
  725.     pass_message_args (con, tag, ":%s %s %s", sender_name, chan->name,
  726.                pkt);
  727.     notify_ops (chan, "%s [ops/%s]: %s", sender_name, chan->name, pkt);
  728. }
  729.  
  730. static void
  731. add_flag (char *d, int dsize, char *flag, int bit, int onmask, int offmask)
  732. {
  733.     if ((onmask & bit) || (offmask & bit))
  734.     {
  735.     int     len = strlen (d);
  736.  
  737.     snprintf (d + len, dsize - len, "%s%c%s", dsize > 0 ? " " : "",
  738.           (onmask & bit) ? '+' : '-', flag);
  739.     }
  740. }
  741.  
  742. static int
  743. channel_mode_bit (const char *s)
  744. {
  745.     if (!strcasecmp ("topic", s))
  746.     return ON_CHANNEL_TOPIC;
  747.     if (!strcasecmp ("registered", s))
  748.     return ON_CHANNEL_REGISTERED;
  749.     if (!strcasecmp ("private", s))
  750.     return ON_CHANNEL_PRIVATE;
  751.     if (!strcasecmp ("invite", s))
  752.     return ON_CHANNEL_INVITE;
  753.     if (!strcasecmp ("moderated", s))
  754.     return ON_CHANNEL_MODERATED;
  755.     return -1;
  756. }
  757.  
  758. #define MAX_MODE 5
  759.  
  760. /* 10209 [ :<sender> ] <channel> [mode]
  761.    change/display channel mode */
  762. HANDLER (channel_mode)
  763. {
  764.     char   *senderName;
  765.     USER   *sender;
  766.     CHANNEL *chan;
  767.     int     onmask = 0, offmask = 0, bit;
  768.     int     ac = -1;
  769.     char   *av[MAX_MODE + 1];
  770.     int     j;
  771.  
  772.     (void) len;
  773.     ASSERT (validate_connection (con));
  774.     if (pop_user_server (con, tag, &pkt, &senderName, &sender))
  775.     return;
  776.     if (pkt)
  777.     ac = split_line (av, FIELDS (av), pkt);
  778.     if (ac < 1)
  779.     {
  780.     unparsable (con);
  781.     return;
  782.     }
  783.     chan = hash_lookup (Channels, av[0]);
  784.     if (!chan)
  785.     {
  786.     nosuchchannel (con);
  787.     return;
  788.     }
  789.  
  790.     /* if no args are given, return the current mode */
  791.     if (ac == 1)
  792.     {
  793.     CHECK_USER_CLASS ("channel_mode");
  794.     send_cmd (con, MSG_SERVER_NOSUCH, "mode for channel %s%s%s%s%s%s%s",
  795.           chan->name,
  796.           (chan->flags & ON_CHANNEL_PRIVATE) ? " +PRIVATE" :
  797.           "",
  798.           (chan->flags & ON_CHANNEL_MODERATED) ? " +MODERATED"
  799.           : "",
  800.           (chan->flags & ON_CHANNEL_INVITE) ? " +INVITE" : "",
  801.           (chan->flags & ON_CHANNEL_TOPIC) ? " +TOPIC" : "",
  802.           (chan->flags & ON_CHANNEL_REGISTERED) ? " +REGISTERED" : "",
  803.           (chan->flags & ON_CHANNEL_QUIET) ? " +QUIET" : "");
  804.     return;
  805.     }
  806.  
  807.     /* check for permission */
  808.     if (sender && sender->level < LEVEL_MODERATOR
  809.     && !is_chanop (chan, sender))
  810.     {
  811.     if (ISUSER (con))
  812.         send_cmd (con, MSG_SERVER_NOSUCH,
  813.             "channel mode failed: you are not operator");
  814.     return;
  815.     }
  816.  
  817.     for (j = 1; j < ac; j++)
  818.     {
  819.     if (*av[j] != '+' && *av[j] != '-')
  820.     {
  821.         if (ISUSER (con))
  822.         send_cmd (con, MSG_SERVER_NOSUCH,
  823.               "channel mode failed: invalid prefix");
  824.         continue;
  825.     }
  826.  
  827.     bit = channel_mode_bit (av[j] + 1);
  828.     if (bit == ON_CHANNEL_REGISTERED)
  829.     {
  830.         if (sender && sender->level < LEVEL_MODERATOR)
  831.         {
  832.         if (ISUSER (con))
  833.             send_cmd (con, MSG_SERVER_NOSUCH,
  834.                   "channel mode failed: only mods+ can register channels");
  835.         continue;
  836.         }
  837.     }
  838.     else if (bit == -1)
  839.     {
  840.         if (ISUSER (con))
  841.         send_cmd (con, MSG_SERVER_NOSUCH,
  842.               "channel mode failed: invalid mode");
  843.         continue;        /* unknown flag */
  844.     }
  845.  
  846.     if (*av[j] == '+')
  847.     {
  848.         onmask |= bit;
  849.         offmask &= ~bit;
  850.         if ((chan->flags & bit) == 0)
  851.         chan->flags |= bit;
  852.         else
  853.         onmask &= ~bit;    /* already set */
  854.     }
  855.     else
  856.     {
  857.         ASSERT (*av[j] == '-');
  858.         offmask |= bit;
  859.         onmask &= ~bit;
  860.         if (chan->flags & bit)
  861.         chan->flags &= ~bit;
  862.         else
  863.         offmask &= ~bit;    /* not set */
  864.     }
  865.     }
  866.  
  867.     /* only take action if something actually changed */
  868.     if (onmask || offmask)
  869.     {
  870.     char    msg[512];
  871.  
  872.     msg[0] = 0;
  873.     add_flag (msg, sizeof (msg), "PRIVATE", ON_CHANNEL_PRIVATE, onmask,
  874.           offmask);
  875.     add_flag (msg, sizeof (msg), "MODERATED", ON_CHANNEL_MODERATED,
  876.           onmask, offmask);
  877.     add_flag (msg, sizeof (msg), "INVITE", ON_CHANNEL_INVITE, onmask,
  878.           offmask);
  879.     add_flag (msg, sizeof (msg), "TOPIC", ON_CHANNEL_TOPIC, onmask,
  880.           offmask);
  881.     add_flag (msg, sizeof (msg), "REGISTERED", ON_CHANNEL_REGISTERED,
  882.           onmask, offmask);
  883.     notify_ops (chan, "%s%s changed mode on channel %s:%s",
  884.             !sender ? "Server " : "", senderName, chan->name, msg);
  885.  
  886.     if (!chan->local)
  887.         pass_message_args (con, tag, ":%s %s %s", senderName,
  888.                    chan->name, msg);
  889.  
  890.     /* handle the -REGISTERED case here.  if there are no users in the
  891.      * channel, we get rid of it
  892.      */
  893.     if ((offmask & ON_CHANNEL_REGISTERED) && !chan->users)
  894.     {
  895.         log ("channel_mode: destroying channel %s", chan->name);
  896.         hash_remove (Channels, chan->name);
  897.     }
  898.     }
  899. }
  900.  
  901. static int
  902. is_member (CHANNEL * chan, USER * user)
  903. {
  904.     LIST   *list;
  905.     CHANUSER *chanUser;
  906.  
  907.     for (list = chan->users; list; list = list->next)
  908.     {
  909.     chanUser = list->data;
  910.     if (chanUser->user == user)
  911.         return 1;
  912.     }
  913.     return 0;
  914. }
  915.  
  916. /* 10210 [ :<sender> ] <channel> <user>
  917.    invite a user to a channel */
  918. HANDLER (channel_invite)
  919. {
  920.     USER   *sender, *user;
  921.     int     ac = -1;
  922.     char   *av[2];
  923.     char   *sender_name;
  924.     LIST   *list;
  925.     CHANNEL *chan;
  926.  
  927.     (void) len;
  928.     ASSERT (validate_connection (con));
  929.     if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
  930.     return;
  931.     if (pkt)
  932.     ac = split_line (av, FIELDS (av), pkt);
  933.     if (ac < 2)
  934.     {
  935.     unparsable (con);
  936.     return;
  937.     }
  938.     chan = hash_lookup (Channels, av[0]);
  939.     if (!chan)
  940.     {
  941.     nosuchchannel (con);
  942.     return;
  943.     }
  944.     if (ISSERVER (con) && chan->local)
  945.     {
  946.     log ("channel_invite: server %s accessed local channel %s",
  947.          con->host, chan->name);
  948.     return;
  949.     }
  950.     if (!(chan->flags & ON_CHANNEL_INVITE))
  951.     {
  952.     if (ISUSER (con))
  953.         send_cmd (con, MSG_SERVER_NOSUCH, "channel is not invite only");
  954.     return;
  955.     }
  956.     /*ensure the user is on this channel */
  957.     if (sender->level < LEVEL_MODERATOR && !is_member (chan, sender))
  958.     {
  959.     permission_denied (con);
  960.     return;
  961.     }
  962.     user = hash_lookup (Users, av[1]);
  963.     if (!user)
  964.     {
  965.     nosuchuser (con);
  966.     return;
  967.     }
  968.     if (is_member (chan, user))
  969.     {
  970.     if (ISUSER (con))
  971.         send_cmd (con, MSG_SERVER_NOSUCH, "user is already in channel");
  972.     return;
  973.     }
  974.     /*ensure the user is not already invited */
  975.     if (list_find (chan->invited, user))
  976.     return;            /* already invited */
  977.  
  978.     list = CALLOC (1, sizeof (LIST));
  979.     list->data = user;
  980.     list->next = chan->invited;
  981.     chan->invited = list;
  982.  
  983.     if (!chan->local)
  984.     pass_message_args (con, tag, ":%s %s %s", sender->nick, chan->name,
  985.                user->nick);
  986.  
  987.     if (ISUSER (user->con))
  988.     {
  989.     send_cmd (user->con, MSG_SERVER_NOSUCH,
  990.           "%s invited you to channel %s", sender->nick, chan->name);
  991.     }
  992.  
  993.     notify_ops (chan, "%s invited %s to channel %s", sender->nick, user->nick,
  994.         chan->name);
  995. }
  996.  
  997. /* 10213/10214 [:sender] <channel> <user> ["reason"]
  998.    channel muzzle/unmuzzle */
  999. HANDLER (channel_muzzle)
  1000. {
  1001.     char   *senderName;
  1002.     USER   *sender, *user;
  1003.     CHANNEL *chan;
  1004.     LIST   *list;
  1005.     CHANUSER *chanUser;
  1006.     int     ac = -1;
  1007.     char   *av[3];
  1008.  
  1009.     (void) len;
  1010.     ASSERT (validate_connection (con));
  1011.     if (pop_user_server (con, tag, &pkt, &senderName, &sender))
  1012.     return;
  1013.     if (pkt)
  1014.     ac = split_line (av, FIELDS (av), pkt);
  1015.     if (ac < 1)
  1016.     {
  1017.     unparsable (con);
  1018.     return;
  1019.     }
  1020.     chan = hash_lookup (Channels, av[0]);
  1021.     if (!chan)
  1022.     {
  1023.     nosuchchannel (con);
  1024.     return;
  1025.     }
  1026.  
  1027.     /* list muzzled users */
  1028.     if (ac == 1)
  1029.     {
  1030.     LIST   *list;
  1031.  
  1032.     CHECK_USER_CLASS ("channel_muzzle");
  1033.     send_cmd (con, MSG_CLIENT_PRIVMSG,
  1034.           "ChanServ muzzled users on channel %s:", chan->name);
  1035.     for (list = chan->users; list; list = list->next)
  1036.     {
  1037.         chanUser = list->data;
  1038.         if (chanUser->flags & ON_CHANNEL_VOICE)
  1039.         send_cmd (con, MSG_CLIENT_PRIVMSG, "ChanServ %s",
  1040.               chanUser->user->nick);
  1041.     }
  1042.     return;
  1043.     }
  1044.  
  1045.     /* find target user */
  1046.     user = hash_lookup (Users, av[1]);
  1047.     if (!user)
  1048.     {
  1049.     nosuchuser (con);
  1050.     return;
  1051.     }
  1052.  
  1053.     if (sender && sender->level < LEVEL_MODERATOR
  1054.     && !is_chanop (chan, sender))
  1055.     {
  1056.     if (ISUSER (con))
  1057.         send_cmd (con, MSG_SERVER_NOSUCH,
  1058.             "channel muzzle failed: you are not operator");
  1059.     return;
  1060.     }
  1061.  
  1062.     for (list = chan->users; list; list = list->next)
  1063.     {
  1064.     chanUser = list->data;
  1065.     if (chanUser->user == user)
  1066.     {
  1067.         if (tag == MSG_CLIENT_CHANNEL_MUZZLE)
  1068.         {
  1069.         chanUser->flags |= ON_CHANNEL_MUZZLED;
  1070.         }
  1071.         else
  1072.         chanUser->flags &= ~ON_CHANNEL_MUZZLED;
  1073.         if (ISUSER (chanUser->user->con))
  1074.         {
  1075.         char   *who;
  1076.  
  1077.         if (sender && sender->cloaked
  1078.             && chanUser->user->level < LEVEL_MODERATOR)
  1079.             who = "Operator";
  1080.         else
  1081.             who = senderName;
  1082.  
  1083.         send_cmd (chanUser->user->con, MSG_SERVER_NOSUCH,
  1084.               "%s%s %smuzzled you on channel %s: %s",
  1085.               !sender ? "Server " : "", who,
  1086.               (chanUser->flags & ON_CHANNEL_MUZZLED) ? "" : "un",
  1087.               chan->name, (ac > 2) ? av[2] : "");
  1088.         }
  1089.         notify_ops (chan, "%s%s %smuzzled %s on channel %s: %s",
  1090.             !sender ? "Server " : "",
  1091.             senderName,
  1092.             (chanUser->flags & ON_CHANNEL_MUZZLED) ? "" : "un",
  1093.             user->nick, chan->name, (ac > 2) ? av[2] : "");
  1094.         break;
  1095.     }
  1096.     }
  1097.     if (!chan->local)
  1098.     pass_message_args (con, tag, ":%s %s %s \"%s\"", senderName,
  1099.                chan->name, user->nick, (ac > 2) ? av[2] : "");
  1100. }
  1101.